package com.bluexmicro.bluetooth.peripheral.handler

import android.annotation.SuppressLint
import android.bluetooth.BluetoothGatt
import com.bluexmicro.bluetooth.LogUtils
import com.bluexmicro.bluetooth.model.GattStatus
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

typealias RequestMtuCallback = (
    gatt: BluetoothGatt,
    mtu: Int,
    status: Int
) -> Unit

class RequestMtuHandler {

    private var callback: RequestMtuCallback? = null
    private var cancellableContinuation: CancellableContinuation<Result<Int>>? = null

    fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {
        callback?.invoke(gatt, mtu, status)
    }

    private fun setCallback(cb: RequestMtuCallback) {
        this.callback = cb
    }

    fun isActive(): Boolean {
        return cancellableContinuation?.isActive == true
    }

    @SuppressLint("MissingPermission")
    suspend fun execute(
        gatt: BluetoothGatt,
        size: Int
    ) = suspendCancellableCoroutine<Result<Int>> {
        cancellableContinuation = it
        setCallback { _, mtuSize, status ->
            this.callback = null
            if (it.isActive) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    it.resume(Result.success(mtuSize))
                } else {
                    val reason = GattStatus.fromValue(status).name
                    it.resume(Result.failure(Throwable("Request MTU Size Failed, gatt status: $status, reason: $reason")))
                }
            }
        }

        if (it.isActive) {
            val res = gatt.requestMtu(size)
            LogUtils.sendLog(
                mapOf(
                    "mac" to gatt.device.address,
                    "call method" to "requestMtu",
                    "detail" to if (res) "done" else "failed"
                )
            )

            if (!res) {
                this.callback = null
                it.resume(Result.failure(Throwable("Request MTU Size Failed!")))
            }
            it.invokeOnCancellation {
                this.callback = null
            }
        }
    }
}